<?php

namespace humhub\modules\api\controllers;

use Yii;
use yii\web\HttpException;
use yii\web\UploadedFile;
use yii\helpers\FileHelper;
use humhub\models\Setting;
use humhub\modules\content\components\ContentActiveRecord;
use humhub\modules\content\components\ContentAddonActiveRecord;
use humhub\modules\file\models\File;
use humhub\modules\api\models\FileAli;

use yii\filters\auth\CompositeAuth;
use yii\filters\auth\HttpBearerAuth;

/**
 * 上传, 显示, 删除文件
 */
class FileController extends Base4Controller
{

    /**
     * @inheritdoc
     */
    public function behaviors(){
        $behaviors = parent::behaviors();
        $behaviors['authenticator'] = [
            'class' => CompositeAuth::className(),
            'authMethods' => [
                //QueryParamAuth::className(),
                HttpBearerAuth::className(),
            ],
        ];

        $behaviors['acl'] = [
            'class' => \humhub\components\behaviors\AccessControl::className(),
            'guestAllowedActions' => ['download']
        ];

        return $behaviors;
    }

    /**
     * 上传文件【!!!上传身份证等隐私文件请勿使用次接口!!!】
     *
     * POST /api/file/upload
     *
     * post.files[]  文件
     *
     * objectModel  在编辑内容新增图片时, 编辑帖子内容赋值:[post]; 评论内容:[comment]
     *
     * objectId 在编辑内容新增图片时,传值内容的ID
     *
     * @return array files
     */
    public function actionUpload(){
        return $this->upload2file();
    }

    /**
     * 上传文件 ( 适用于身份证等隐私文件 )
     *
     * POST /api/file/uploadsafe
     *
     * 传参和返回同: /api/file/upload
     */
    public function actionUploadsafe(){
        return $this->upload2file(1);
    }

    private function upload2file($safe=0){
        // Object which the uploaded file(s) belongs to (optional)
        $object = null;
        if( Yii::$app->request->post('objectModel')=='post' ){
            $objectModel = 'humhub\modules\post\models\Post';
        }elseif( Yii::$app->request->post('objectModel')=='comment' ){
            $objectModel = 'humhub\modules\comment\models\Comment';
        }else{
            $objectModel = '';
        }
        $objectId = Yii::$app->request->post('objectId');
        if ($objectModel != "" && $objectId != "" && \humhub\libs\Helpers::CheckClassType($objectModel, \yii\db\ActiveRecord::className())) {
            $givenObject = $objectModel::findOne(['id' => $objectId]);
            // Check if given object is HActiveRecordContent or HActiveRecordContentAddon and can be written by the current user
            if ($givenObject !== null && ($givenObject instanceof ContentActiveRecord || $givenObject instanceof ContentAddonActiveRecord) && $givenObject->content->canWrite()) {
                $object = $givenObject;
            }
        }

        $files = array();
        $up_num = 0;
        foreach (UploadedFile::getInstancesByName('files') as $cFile) {
            $f = $this->handleFileUpload($cFile, $object, $safe);
            if( $f !== false ){
                $files[] = $f;
                $up_num++;
            }
            if( $up_num>=9 ){ //Max:9
                break;
            }
        }

        if( count($files) ){
            return $files;
            //return ['files' => $files];
        }
        Yii::$app->params['res-success'] = false;
        return false;

    }

    /**
     * @inheritdoc
     */
    protected function handleFileUpload($cFile, $object = null, $safe=0){
        $nArr = explode('.', $cFile->name);
        $ext = $nArr[count($nArr)-1];
        $exts = ['docx', 'doc', 
            'pdf', 
            'xls', 'xlsx', 
            'ppt', 'pptx',
            'jpg', 'jpeg', 'png', 'gif',
            'mp4',
        ];
        if( ! in_array($ext, $exts) ){
            return false;
        }
        $output = array();

        //Ali upload
        $file = new FileAli();
        //Local upload
        //$file = new File();

        $file->setUploadedFile($cFile);

        if ($object != null) {
            $file->object_id = $object->getPrimaryKey();
            $file->object_model = $object->className();
        }

        if ( ! $file->validate() ) {
            return false;
        }
        if( ($ossurl = $file->oss_up($safe)) === false ){
            return false;
        }
        $file->ossurl = $ossurl;

        if ( $file->save()) {
            $output['error'] = false;
            $output['guid'] = $file->guid;
            $output['name'] = $file->file_name;
            $output['title'] = $file->title;
            $output['size'] = $file->size;
            $output['mimeIcon'] = \humhub\libs\MimeHelper::getMimeIconClassByExtension($file->getExtension());
            $output['mimeBaseType'] = $file->getMimeBaseType();
            $output['mimeSubType'] = $file->getMimeSubType();
            $output['url'] = $file->getUrl("", false);
            $output['thumbnailUrl'] = $file->getPreviewImageUrl(400, 400);
        } else {
            $output['error'] = true;
            $output['errors'] = $file->getErrors();
        }

        $output['name'] = $file->file_name;
        $output['size'] = $file->size;
        $output['deleteUrl'] = "";
        $output['deleteType'] = "";
        $output['thumbnailUrl'] = "";

        return $output;
    }

    /**
     * 显示图片/下载文件
     *
     * GET [URL]/file/file/download?guid=[guid]#.[mimeSubType] 图片
     *
     * GET [URL]/file/file/download?guid=[guid]&suffix=pi_200x200  指定尺寸图片
     *
     * GET [URL]/file/file/download?guid=[guid]                文件
     */
    public function actionDownload(){
        // GUID of file
        $guid = Yii::$app->request->get('guid');
        // Force Download Flag
        $download = Yii::$app->request->get('download', 0);
        // Optional suffix of file (e.g. scaled variant of image)
        $suffix = Yii::$app->request->get('suffix');

        $file = File::findOne(['guid' => $guid]);
        if ($file == null) {
            throw new HttpException(404, Yii::t('FileModule.controllers_FileController', 'Could not find requested file!'));
        }
        if (!$file->canRead()) {
            throw new HttpException(401, Yii::t('FileModule.controllers_FileController', 'Insufficient permissions!'));
        }

        if (!file_exists($file->getStoredFilePath($suffix))) {
            throw new HttpException(404, Yii::t('FileModule.controllers_FileController', 'Could not find requested file!'));
        }

        $options = [
            'inline' => false,
            'mimeType' => FileHelper::getMimeTypeByExtension($file->getFilename($suffix))
        ];

        if ($download != 1 && in_array($options['mimeType'], Yii::$app->getModule('file')->inlineMimeTypes)) {
            $options['inline'] = true;
        }

        if (!Yii::$app->getModule('file')->settings->get('useXSendfile')) {
            Yii::$app->response->sendFile($file->getStoredFilePath($suffix), $file->getFilename($suffix), $options);
        } else {
            $filePath = $file->getStoredFilePath($suffix);

            if (strpos($_SERVER['SERVER_SOFTWARE'], 'nginx') === 0) {
                // set nginx specific X-Sendfile header name
                $options['xHeader'] = 'X-Accel-Redirect';
                // make path relative to docroot
                $docroot = rtrim($_SERVER['DOCUMENT_ROOT'], DIRECTORY_SEPARATOR);
                if (substr($filePath, 0, strlen($docroot)) == $docroot) {
                    $filePath = substr($filePath, strlen($docroot));
                }
            }

            Yii::$app->response->xSendFile($filePath, $file->getFilename($suffix), $options);
        }
    }

    /**
     * 删除文件
     *
     * POST /api/file/delete
     *
     * post.guid 文件guid
     *
     * @return boolean
     */
    public function actionDelete(){
        $this->forcePostRequest();

        $guid = Yii::$app->request->post('guid');
        $file = File::findOne(['guid' => $guid]);

        if ($file == null) {
            throw new HttpException(404, Yii::t('FileModule.controllers_FileController', 'Could not find requested file!'));
        }

        if (!$file->canDelete()) {
            throw new HttpException(401, Yii::t('FileModule.controllers_FileController', 'Insufficient permissions!'));
        }

        $file->delete();
        return true;
    }
}
